package br.com.programacao.concorrente.entidades;

import java.io.File;
import java.util.Calendar;
import java.util.Date;

/**
 * A classe Consumidor é responsável por ser a base da Thread e consumir o
 * buffer. Ela implementa a interface Runnable e será instanciada em Thread
 */
public class Consumidor implements Runnable {

    private final Buffer buffer;
    private final int execution;

    /**
     * Para instanciar um Consumidor, é necessário informar qual é o numero da
     * execução e em qual buffer ele irá consumir (referência do buffer).
     *
     * @param buffer
     * @param execution
     */
    public Consumidor(Buffer buffer, int execution) {
        this.buffer = buffer;
        this.execution = execution;
    }

    /**
     * Metodo que será executado na Thread
     */
    @Override
    public void run() {
        //Pega o inicio do processamento
        long timeInitThread = getTimeMillis();
        int qtdTheads = 0;
        final String inicioThread = "Inicio da thread" + " " + Thread.currentThread().getName() + " "
                + " Execução:" + this.execution + " "
                + Calendar.getInstance().getTime();

        //Grava no log o inicio
        Log.getLogger(this.getClass()).info(inicioThread);

        //Para a primeira chave do buffer. Caso ela não exista, não é executado o 
        //loop de execução.
        String next = buffer.getNext();
        while (next != null) {
            try {
                qtdTheads++;
                long inicio = getTimeMillis();
                Date dtInicio = Calendar.getInstance().getTime();

                File file = buffer.getFile(next);
                String id = gravaLogInicio(file, dtInicio);

                Thread.sleep(Constantes.INTERVAL_THREAD);

                gravaLogFim(id, file, inicio);
            } catch (InterruptedException | NullPointerException ex) {
                Log.getLogger(this.getClass()).error(ex);
            } finally {
                next = buffer.getNext();
            }
        }
        long timeEndThread = getTimeMillis();
        final String terminoThread = "Termino da thread" + " " + Thread.currentThread().getName()
                + " Execução:" + this.execution + " "
                + " " + Calendar.getInstance().getTime();
        Log.getLogger(this.getClass()).info(terminoThread);
        Log.includeLogFileExecution(this.execution, (timeEndThread - timeInitThread), qtdTheads);
    }

    /**
     * Grava no log o fim do processamento do arquivo
     *
     * @param file
     * @param dtInicio
     * @return id do pedido
     * @throws NullPointerException
     */
    private String gravaLogInicio(File file, Date dtInicio) throws NullPointerException {
        String id = String.valueOf(Thread.currentThread().getName());
        String inicioLog = "Thread #" + id + " Pedido #" + file.getName() + " Inicio:" + dtInicio;
        Log.getLogger(this.getClass()).debug(inicioLog);
        return id;
    }

    /**
     * Grava no log o fim do processamento do arquivo
     *
     * @param id
     * @param file
     * @param inicio
     * @throws NullPointerException
     */
    private void gravaLogFim(String id, File file, long inicio) throws NullPointerException {
        String fimLog = "Thread #" + id + " Pedido #" + file.getName() + " Termino:" + Calendar.getInstance().getTime();
        Log.getLogger(this.getClass()).debug(fimLog);

        long fim = getTimeMillis();
        Log.includeLogFileThread(this.execution, id, file.getName(), (fim - inicio));
    }

    /**
     * Retorna os milissegundos do sistema.
     * Criei o motodo para testar a captura dos milissegundos
     * @return
     */
    private long getTimeMillis() {
        //return  System.currentTimeMillis();  
        return Calendar.getInstance().getTimeInMillis();
        //return Calendar.getInstance().getTime();
    }
}
